;; Copyright (C) 2001-2025 Free Software Foundation, Inc.
;;
;; This file is part of GCC.
;;
;; GCC is free software; you can redistribute it and/or modify it under
;; the terms of the GNU General Public License as published by the Free
;; Software Foundation; either version 3, or (at your option) any later
;; version.
;;
;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
;; WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
;; for more details.
;;
;; Under Section 7 of GPL version 3, you are granted additional
;; permissions described in the GCC Runtime Library Exception, version
;; 3.1, as published by the Free Software Foundation.
;;
;; You should have received a copy of the GNU General Public License and
;; a copy of the GCC Runtime Library Exception along with this program;
;; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
;; <http://www.gnu.org/licenses/>.
;;
;; This code is derived from mulsi3.S, observing that the mstep*16-based
;; multiplications there, from which it is formed, are actually
;; zero-extending; in gcc-speak "umulhisi3".  The difference to *this*
;; function is just a missing top mstep*16 sequence and shifts and 64-bit
;; additions for the high part.  Compared to an implementation based on
;; calling __Mul four times (see default implementation of umul_ppmm in
;; longlong.h), this will complete in a time between a fourth and a third
;; of that, assuming the value-based optimizations don't strike.  If they
;; all strike there (very often) but none here, we still win, though by a
;; lesser margin, due to lesser total overhead.

#define L(x) .x
#define CONCAT1(a, b) CONCAT2(a, b)
#define CONCAT2(a, b) a ## b

#ifdef __USER_LABEL_PREFIX__
# define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
#else
# define SYM(x) x
#endif

	.global SYM(__umulsidi3)
	.type	SYM(__umulsidi3),@function
SYM(__umulsidi3):
#if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10
;; Can't have the mulu.d last on a cache-line, due to a hardware bug.  See
;; the documentation for -mmul-bug-workaround.
;; Not worthwhile to conditionalize here.
	.p2alignw 2,0x050f
	mulu.d $r11,$r10
	ret
	move $mof,$r11
#else
	move.d $r11,$r9
	bound.d $r10,$r9
	cmpu.w 65535,$r9
	bls L(L3)
	move.d $r10,$r12

	move.d $r10,$r13
	movu.w $r11,$r9 ; ab*cd = (a*c)<<32 (a*d + b*c)<<16 + b*d

;; We're called for floating point numbers very often with the "low" 16
;; bits zero, so it's worthwhile to optimize for that.

	beq L(L6)	; d == 0?
	lslq 16,$r13

	beq L(L7)	; b == 0?
	clear.w $r10

	mstep $r9,$r13	; d*b
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13
	mstep $r9,$r13

L(L7):
	test.d $r10
	mstep $r9,$r10	; d*a
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10
	mstep $r9,$r10

;; d*a in $r10, d*b in $r13, ab in $r12 and cd in $r11
;; $r9 = d, need to do b*c and a*c; we can drop d.
;; so $r9 is up for use and we can shift down $r11 as the mstep
;; source for the next mstep-part.

L(L8):
	lsrq 16,$r11
	move.d $r12,$r9
	lslq 16,$r9
	beq L(L9)	; b == 0?
	mstep $r11,$r9

	mstep $r11,$r9	; b*c
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
	mstep $r11,$r9
L(L9):

;; d*a in $r10, d*b in $r13, c*b in $r9, ab in $r12 and c in $r11,
;; need to do a*c.  We want that to end up in $r11, so we shift up $r11 to
;; now use as the destination operand.  We'd need a test insn to update N
;; to do it the other way round.

	lsrq 16,$r12
	lslq 16,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11
	mstep $r12,$r11

;; d*a in $r10, d*b in $r13, c*b in $r9, a*c in $r11 ($r12 free).
;; Need (a*d + b*c)<<16 + b*d into $r10 and
;; a*c + (a*d + b*c)>>16 plus carry from the additions into $r11.

	add.d $r9,$r10	; (a*d + b*c) - may produce a carry.
	scs $r12	; The carry corresponds to bit 16 of $r11.
	lslq 16,$r12
	add.d $r12,$r11	; $r11 = a*c + carry from (a*d + b*c).

#if defined (__CRIS_arch_version) && __CRIS_arch_version >= 8
	swapw $r10
	addu.w $r10,$r11 ; $r11 = a*c + (a*d + b*c) >> 16 including carry.
	clear.w $r10	; $r10 = (a*d + b*c) << 16
#else
	move.d $r10,$r9
	lsrq 16,$r9
	add.d $r9,$r11	; $r11 = a*c + (a*d + b*c) >> 16 including carry.
	lslq 16,$r10	; $r10 = (a*d + b*c) << 16
#endif
	add.d $r13,$r10	; $r10 = (a*d + b*c) << 16 + b*d - may produce a carry.
	scs $r9
	ret
	add.d $r9,$r11	; Last carry added to the high-order 32 bits.

L(L6):
	clear.d $r13
	ba L(L8)
	clear.d $r10

L(L11):
	clear.d $r10
	ret
	clear.d $r11

L(L3):
;; Form the maximum in $r10, by knowing the minimum, $r9.
;; (We don't know which one of $r10 or $r11 it is.)
;; Check if the largest operand is still just 16 bits.

	xor $r9,$r10
	xor $r11,$r10
	cmpu.w 65535,$r10
	bls L(L5)
	movu.w $r9,$r13

;; We have ab*cd = (a*c)<<32 + (a*d + b*c)<<16 + b*d, but c==0
;; so we only need (a*d)<<16 + b*d with d = $r13, ab = $r10.
;; Remember that the upper part of (a*d)<<16 goes into the lower part
;; of $r11 and there may be a carry from adding the low 32 parts.
	beq L(L11)	; d == 0?
	move.d $r10,$r9

	lslq 16,$r9
	beq L(L10)	; b == 0?
	clear.w $r10

	mstep $r13,$r9	; b*d
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
	mstep $r13,$r9
L(L10):
	test.d $r10
	mstep $r13,$r10	; a*d
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	move.d $r10,$r11
	lsrq 16,$r11
	lslq 16,$r10
	add.d $r9,$r10
	scs $r12
	ret
	add.d $r12,$r11

L(L5):
;; We have ab*cd = (a*c)<<32 + (a*d + b*c)<<16 + b*d, but a and c==0
;; so b*d (with min=b=$r13, max=d=$r10) it is.  As it won't overflow the
;; 32-bit part, just set $r11 to 0.

	lslq 16,$r10
	clear.d $r11

	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	mstep $r13,$r10
	ret
	mstep $r13,$r10
#endif
L(Lfe1):
	.size	SYM(__umulsidi3),L(Lfe1)-SYM(__umulsidi3)
